package com.cx.myioc.core;

import com.cx.myioc.anootation.MyAutowired;
import com.cx.myioc.anootation.MyComponent;
import com.sun.org.apache.bcel.internal.generic.NEW;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.FileNameMap;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhangshuai
 * @version V1.0
 * @Project Java2_26
 * @Package com.cx.myioc.core
 * @Description:
 * @Date 2025/5/29 9:07
 */

public class MyApplicationContext {
    //1.扫描包路径，找到需要的注解@MyComponen,在容器中创建对象
    //2.找到对象中需要的注解@MyAutowired，在容器中找到对应的对象，注入到属性中
    // bean容器 key 类名   value 类对象
    Map<String,Object> beanDefinitions = new HashMap<>();
    //接口容器 key 接口名   value 接口对象
    Map<Class<?>,Object> interfaceToBeanMap = new HashMap<>();

    private String packageName;

    public MyApplicationContext(String packageName) {
       try {
            if (packageName == null || packageName.trim().equals("")) {
            throw new RuntimeException("包名不能为空");
        }
        //包路径扫描
        String replace = packageName.replace(".", "/");
        //获取路径
        URL resource = MyApplicationContext.class.getClassLoader().getResource(replace);
        if (resource == null) {
            throw new RuntimeException("包名不存在");
        }
        //URL和URI的区别
        //URL是URI的子类，URI是URL的超类
        //URL是统一资源定位符，URI是统一资源标识符
        //URL是网络地址，URI是文件地址

            URI dir = resource.toURI();
            if (dir == null) {
                throw new RuntimeException("包名不存在");
            }
            //遍历包路径下的所有文件
            //判断文件是否是class文件
            //判断文件是否是需要的注解@MyComponent
           File dirFile = new File(dir); //根据路径创建文件对象
           if (!dirFile.exists()) {
               throw new RuntimeException("该路径下文件不存在");
           }

           //迭代方法判断file是文件还是目录
           classLoader(dirFile,packageName);

           // 遍历beanDefinitions中的所有bean
/* for (Object bean : beanDefinitions.values()) {
     // 获取bean的Class对象
     Class<?> clazz = bean.getClass();
     // 遍历bean的所有接口
     for (Class<?> iface : clazz.getInterfaces()) {
         // 将接口和对应的bean放入interfaceToBeanMap中
         interfaceToBeanMap.put(iface, bean);
     }
 }*/
           //接口映射

           //依赖注入，判断属性是否有@MyAutowired注解
           for (Object value : beanDefinitions.values()) {
               if(value == null){
                   throw new RuntimeException("对象为空");
               }
               //判断属性是否有@MyAutowired注解
               Class<?> aClass = value.getClass();
               for (Field beanField : aClass.getDeclaredFields()) {
                   if(beanField.isAnnotationPresent(MyAutowired.class)){
                       //进行依赖注入
                       beanField.setAccessible(true); //设置属性可访问
                       if(beanField == null){
                           throw new RuntimeException("属性为空");
                       }else {

                          /* Class<?> fieldType = beanField.getType();
                           Object dependency = interfaceToBeanMap.get(fieldType);
                           if (dependency == null) {
                               System.out.println("Dependency not found for field: " + beanField.getName());
                           } else {
                               beanField.set(value, dependency);
                               System.out.println("Dependency injected for field: " + beanField.getName());
                           }*/
                           String fieldName = beanField.getName();
                           Object bean = beanDefinitions.get(fieldName+"Impl");
                           if(bean == null){
                               throw new RuntimeException("对象为空");
                           }else {
                               beanField.set(value,bean);
                               System.out.println("属性依赖注入: " + beanField.getName());
                           }

                       }}
               }


           }


           System.out.println(resource);
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
           throw new RuntimeException(e);
       }


    }
    //迭代方法判断file是文件还是目录
    private void classLoader(File dirFile, String packageName) {
        //获取文件列表
        File[] files = dirFile.listFiles();
        if (files == null) {
            throw new RuntimeException("该路径下文件不存在");
        }
        for (File file : files) {
            //判断当前文件是否是目录，如果是目录，递归调用
            if (file.isDirectory()) {
                classLoader(file,packageName+"."+file.getName());
            }else {
                //如果文件不是，判断它是不是类文件，.class文件
                if(file.getName().endsWith(".class")){
                    try {  //获取类名
                    String className = file.getName().replace(".class", "");
                    String classNamePath = packageName + "." + className;


                        Class<?> aClass = Class.forName(classNamePath);
                        //判断aClass是否有@MyComponent创建对象
                        if(aClass.isAnnotationPresent(MyComponent.class)){
                            Object bean = aClass.getDeclaredConstructor().newInstance();
                            //bean类名首字母小写
                            className= className.substring(0, 1).toLowerCase() + className.substring(1);

                            //将对象放入容器中
                            beanDefinitions.put(className,bean);
                            System.out.println("创建对象成功"+className);
                        }
                    } catch (ClassNotFoundException e) {
                        throw new RuntimeException(e);
                    } catch (InvocationTargetException e) {
                        throw new RuntimeException(e);
                    } catch (InstantiationException e) {
                        throw new RuntimeException(e);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    } catch (NoSuchMethodException e) {
                        throw new RuntimeException(e);
                    }


                    //判断类上是否有@MyComponent,需要Class对象
                    //  isAnnotationPresent(Class<? extends Annotation> annotationClass)

                }
            }
        }
    }
    public Object getBean(String beanName) {

        return beanDefinitions.get(beanName);
    }
}